from PySide6.QtWidgets import (QApplication, QMainWindow, QTextEdit, QPushButton, 
                             QVBoxLayout, QHBoxLayout, QWidget, QUndoView)
from PySide6.QtGui import QUndoStack, QUndoCommand
from PySide6.QtCore import Qt


class SetTextCommand(QUndoCommand):
    """用于文本修改的撤销命令（支持初始文本和后续修改）"""
    def __init__(self, text_edit, new_text, old_text, description):
        super().__init__(description)
        self.text_edit = text_edit
        self.new_text = new_text  # 操作后的文本
        self.old_text = old_text  # 操作前的文本（用于撤销）

    def redo(self):
        """执行命令：应用新文本"""
        self.text_edit.setPlainText(self.new_text)

    def undo(self):
        """撤销命令：恢复旧文本"""
        self.text_edit.setPlainText(self.old_text)


class UndoViewDemo(QMainWindow):
    def __init__(self):
        super().__init__()
        self.undo_stack = QUndoStack(self)  # 初始化撤销栈
        self.init_ui()
        self.set_initial_text()  # 设置初始文本并添加到撤销栈

    def init_ui(self):
        self.setWindowTitle("QUndoView 初始文本示例")
        self.setGeometry(100, 100, 800, 500)

        # 1. 文本编辑区
        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("编辑文本...")

        # 2. 操作按钮
        self.add_btn = QPushButton("添加内容")
        self.add_btn.clicked.connect(self.add_text)
        
        self.clear_btn = QPushButton("清空文本")
        self.clear_btn.clicked.connect(self.clear_text)

        # 3. 撤销/重做按钮
        self.undo_btn = QPushButton("撤销 (Ctrl+Z)")
        self.redo_btn = QPushButton("重做 (Ctrl+Y)")
        self.undo_btn.clicked.connect(self.undo_stack.undo)
        self.redo_btn.clicked.connect(self.undo_stack.redo)

        # 4. QUndoView：展示撤销历史（包含初始文本）
        self.undo_view = QUndoView(self.undo_stack)
        self.undo_view.setEmptyLabel("操作历史")
        self.undo_view.setMinimumWidth(200)
        self.undo_view.setMaximumWidth(300)
        # 允许通过双击历史条目直接跳转到对应状态
        self.undo_view.setEditTriggers(QUndoView.EditTrigger.DoubleClicked)

        # 布局管理
        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.clear_btn)
        btn_layout.addWidget(self.undo_btn)
        btn_layout.addWidget(self.redo_btn)

        main_layout = QHBoxLayout()
        # 左侧：文本编辑区 + 按钮
        left_layout = QVBoxLayout()
        left_layout.addWidget(self.text_edit)
        left_layout.addLayout(btn_layout)
        main_layout.addLayout(left_layout, 2)  # 占2/3宽度
        # 右侧：撤销历史视图
        main_layout.addWidget(self.undo_view, 1)  # 占1/3宽度

        central_widget = QWidget()
        self.setLayout(main_layout)
        self.setCentralWidget(central_widget)

        # 绑定撤销栈状态变化（更新按钮可用性）
        self.undo_stack.canUndoChanged.connect(self.undo_btn.setEnabled)
        self.undo_stack.canRedoChanged.connect(self.redo_btn.setEnabled)

    def set_initial_text(self):
        """设置初始文本并添加到撤销栈，使其在QUndoView中显示"""
        initial_text = "这是初始文本（可撤销到此处）"
        # 初始文本的"旧状态"为空（或根据需求设置）
        initial_command = SetTextCommand(
            text_edit=self.text_edit,
            new_text=initial_text,
            old_text="",  # 初始前无内容
            description="初始文本"  # 在QUndoView中显示的描述
        )
        # 将初始命令压入栈，成为第一个历史记录
        self.undo_stack.push(initial_command)
        # 刷新视图（通常自动刷新，此处为保险）
        # self.undo_view.update()

    def add_text(self):
        """添加文本（生成新的撤销命令）"""
        old_text = self.text_edit.toPlainText()
        new_text = old_text + "\n添加了一行新内容"
        # 创建命令（描述会显示在QUndoView中）
        command = SetTextCommand(
            self.text_edit, new_text, old_text, "添加内容"
        )
        self.undo_stack.push(command)

    def clear_text(self):
        """清空文本（生成新的撤销命令）"""
        old_text = self.text_edit.toPlainText()
        new_text = ""
        command = SetTextCommand(
            self.text_edit, new_text, old_text, "清空文本"
        )
        self.undo_stack.push(command)


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    window = UndoViewDemo()
    window.show()
    window.undo_view.show()  # 显示撤销历史窗口
    sys.exit(app.exec())
